package Model.Main;

import Model.Gates.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.ArrayList;

/**
 *
 ** @author citromos ezustfoka
 */
public class Wire {

    private Gate toGate;
    private int toInput;
    private static final Logger logger =
            Logger.getLogger(Wire.class.getName());
    private ArrayList<Wire> childWires;
    private String name;
    protected int call = 0;

    /**
     * Konstrukor
     * @param toGate Gates példány referenciája, aminek a bemenetére kötjük a wire-t. 
     * @param toInput A bemenet száma, ahányas bemenetre akarjuk kötni a wire-t.
     * @return
     * 
     */
    public Wire(Gate toGate, int toInput, String name) {
        this.name = name;
        logger.finest("Wire created.");
        childWires = new ArrayList<Wire>();
        this.toGate = toGate;
        this.toInput = toInput;
    }

    /**
     * A két összekötött elem közti kapcsolat alapja. Az az elem
     * aminek a kimenetére van kötve a wire, az hívja meg a wire-nek ezt a függvényét. Ez
     * hívja, majd meg a másik elem setInput függvényét.
     * @return
     * 
     */
    public void sendValue(Boolean val) throws Exception {
        call++;
        if (call > 5) {
            throw new Exception("instabil");
        }
        logger.log(Level.FINEST, "" + this.getClass().getName() + " " + this.getName() + " is being used to send value to " + toGate.getClass().getName() + " " + toGate.getName() + ", input number: " + toInput + "");
        toGate.setInput(toInput, val);
        logger.log(Level.FINEST, "" + this.getClass().getName() + " " + this.getName() + " is sending values to child wires.");
        if (childWires.isEmpty()) {
            return;
        } else {
            for (Wire w : childWires) {
                w.sendValue(val);
            }
        }
    }

    /**
     * Annak az elemnek a megadása aminek a bemenetére van kötve a wire.
     * @return
     * 
     */
    public Gate getGate() {
        logger.log(Level.FINEST, "" + this.getClass().getName() + " " + this.getName() + " returning the output gate " + toGate.getClass().getName() + " " + toGate.getName() + ".");
        return toGate;
    }

    /**
     * A függvény visszaadja, hogy az adott vezeték hányas bemenetre van kötve.
     * @return
     * 
     */
    public int getWhichInput() {
        logger.log(Level.FINEST, "" + this.getClass().getName() + " " + this.getName() + " returning the output gate input number " + toInput + ".");
        return toInput;
    }

    /**
     * Leszármazott wire hozzáadása. Megörökli a papa értékét.
     * @param w
     * @throws Exception
     */
    public void addChildWire(Wire w) throws Exception {
        if (childWires.contains(w)) {
            throw new Exception("Wire is already exists in the list");
        }
        if (w == this) {
            throw new Exception("Can not add this wire to itself.");
        }
        this.childWires.add(w);
        logger.log(Level.CONFIG, "" + this.getName() + " added child wire " + w.getName() + " to " + w.getGate().getClass().getName() + " " + w.getGate().getName() + ".");
    }

    /**
     * Kitörli a childwire-t
     * @param w a törlendő wire.
     */
    public void delChildWire(Wire w) throws Exception {
        if (!childWires.contains(w)) {
            throw new Exception("No such wire to delete @" + this + " " + this.getName());
        }
        childWires.remove(w);
        return;
    }

    /**
     * Beállítja a wire nevét
     * @param name a név, amit be szeretnénk állítani
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Visszaadja a wire nevét
     * @return
     */
    public String getName() {
        if (this.name == null) {
            return "Undefined";
        }
        return (this.name);
    }

    /**
     * Visszaadja a childwire-k számát.
     * @return
     */
    public int getChildNumber() {
        return (childWires.size());
    }

    /**
     * Visszaadja a childwire-k számát.
     * @return
     */
    public Wire getChildWire(int i) {
        return (childWires.get(i));
    }

    public int getCall() {
        return call;
    }

    public void setCall() {
        call = 0;
    }
}
